package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"unpackitDemo/model"
	"unpackitDemo/util"
)

// gz包的URL下载地址 TODO:（这里用固定的，你也可以用其他的，但是需要注意model中的结构体得跟着改一下）
var GZ_FILE_URL = "https://ton.twimg.com/advertiser-api-async-analytics/SDJ9NgtdiyZwKaR9eEJQ7vOQm1UXJXWmeAmbZ5XmdBJ5Adj6gXadqEGXMPZNQO2H61cJXkcjMGJcQm6bWGyNB-9SZAId0SL9vVMgdoU5M8w3d6yXALPIrtxFTx5Whf3S.json.gz"

// TODO 方法1：根据请求获取到的字节流数据先在本地生成gz文件然后解压，最后处理数据！
// TODO 注意这样处理起来效率比较低，推荐第2种方法！
// 根据url与method获取请求的数据 得到的结果正好是一个[]byte，正好写入文件需要[]byte
func getBytesFromURL(url, method string) ([]byte, error) {
	// TODO：这里可以用http连接池做优化
	client := &http.Client{}
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	// ReadAll返回一个[]byte
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
}

func HandleURLFile(url string) error {
	method := "GET"
	// 请求数据
	bodyBytes, err := getBytesFromURL(url, method)
	if err != nil {
		return err
	}
	// 根据url获取文件名，文件名是url后面那一串
	fileName, fileErr := util.GetGZNameFromURL(url)
	if fileErr != nil {
		return fileErr
	}
	// 将数据写入文件，相比于后面的"压缩"，这种方式生成的文件没办法解压！
	if err := util.WriteDataToFile(fileName, bodyBytes); err != nil {
		return err
	}
	// 解压文件，获取filePath为后面清空文件夹作准备，是相对路径
	destPath, err := util.DecompressionGZ(fileName)
	if err != nil {
		return err
	}
	fmt.Println("destPath>>> ", destPath)
	// 开始处理json文件
	// 去掉 .gz 后缀
	newFileName := fileName[:len(fileName)-3]
	filePath := destPath + newFileName
	var respObj model.TwitterAdCostAge
	jsonFile, err := os.Open(filePath)
	if err != nil {
		return model.NewError("handleURLBody.openJsonFile", err.Error())
	}
	defer jsonFile.Close()
	// 解析
	byteValue, _ := ioutil.ReadAll(jsonFile)
	err = json.Unmarshal([]byte(byteValue), &respObj)
	if err != nil {
		return model.NewError("handleURLBody.json.Unmarshal", err.Error())
	}
	// 验证一下是否成功获取到了对象
	fmt.Println("obj.DataType: ", respObj.DataType)

	// TODO：最后就可以根据业务需求处理结构体对象数据了！写入数据库等等......

	return nil
}

// TODO 方法2：不用在本地生成gz文件，直接将gz文件流压缩为json文件的方法
func HandleURLBody(url string) error {
	//method := "GET"
	// 根据url获取文件名，文件名是url后面那一串
	fileName, fileErr := util.GetGZNameFromURL(url)
	if fileErr != nil {
		//fmt.Println("fileErr>>> ", fileErr)
		return fileErr
	}
	//fmt.Println("fileName>>> ", fileName)
	// 请求数据
	// TODO：这里可以用http连接池做优化
	//client := &http.Client{}
	client := util.GetHttpClient("twitter", nil)

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// 直接将body的数据解析
	destPath, err := util.DecompressionReqBody(fileName, res.Body)
	if err != nil {
		return model.NewError("handleURLFile2", err.Error())
	}
	fmt.Println("destPath>>> ", destPath)

	// 开始处理json文件
	// 去掉 .gz 后缀
	newFileName := fileName[:len(fileName)-3]
	filePath := destPath + newFileName
	var respObj model.TwitterAdCostAge
	jsonFile, err := os.Open(filePath)
	if err != nil {
		return model.NewError("handleURLBody.openJsonFile", err.Error())
	}
	defer jsonFile.Close()
	// 解析
	byteValue, _ := ioutil.ReadAll(jsonFile)
	err = json.Unmarshal([]byte(byteValue), &respObj)
	if err != nil {
		return model.NewError("handleURLBody.json.Unmarshal", err.Error())
	}
	// 验证一下是否成功获取到了对象
	fmt.Println("obj.DataType: ", respObj.DataType)

	// TODO：最后就可以根据业务需求处理结构体对象数据了！写入数据库等等......

	return nil
}

func main() {

	// 方法1
	//if err := HandleURLFile(GZ_FILE_URL); err != nil {
	//	fmt.Println("ERROR>>> ", err)
	//}

	// 方法2
	if err := HandleURLBody(GZ_FILE_URL); err != nil {
		fmt.Println("ERROR>>> ", err)
	}

	// TODO 最后可以将临时存放json文件的目录删掉
	//if removeError := os.RemoveAll(util.GZIPS_PATH); removeError != nil {
	//	fmt.Println("删除目录失败：", removeError)
	//}
}
